//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_idea_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/idea_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_idea"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_idea_api"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectIdeaApiImpl) SetAppraise(ctx context.Context, req *project_idea_api.SetAppraiseRequest) (*project_idea_api.SetAppraiseResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.SetAppraiseResponse{
			Code:   project_idea_api.SetAppraiseResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.SetAppraiseResponse{
			Code:   project_idea_api.SetAppraiseResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.SetAppraiseResponse{
			Code:   project_idea_api.SetAppraiseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.SetAppraiseResponse{
			Code:   project_idea_api.SetAppraiseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	ideaItem, err := idea_dao.IdeaDao.Get(ctx, req.ProjectId, req.IdeaId)
	if err != nil {
		return &project_idea_api.SetAppraiseResponse{
			Code:   project_idea_api.SetAppraiseResponse_CODE_NO_IDEA,
			ErrMsg: "知识点不存在",
		}, nil
	}

	appraiseItem, err := idea_dao.AppraiseDao.Get(ctx, req.IdeaId, sessionItem.UserId)
	if err == nil && appraiseItem.AppraiseType == uint32(req.AppraiseType) {
		return &project_idea_api.SetAppraiseResponse{
			Code: project_idea_api.SetAppraiseResponse_CODE_OK,
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.AppraiseDao.Set(sessCtx, &idea_dao.AppraiseDbItem{
			IdeaId:       req.IdeaId,
			MemberUserId: sessionItem.UserId,
			AppraiseType: uint32(req.AppraiseType),
			TimeStamp:    nowTime,
		})
		if err != nil {
			return nil, err
		}
		agreeCount, err := idea_dao.AppraiseDao.CountByIdea(sessCtx, req.IdeaId, uint32(project_idea_api.APPRAISE_TYPE_APPRAISE_AGREE))
		if err != nil {
			return nil, err
		}
		disagreeCount, err := idea_dao.AppraiseDao.CountByIdea(sessCtx, req.IdeaId, uint32(project_idea_api.APPRAISE_TYPE_APPRAISE_DIS_AGREE))
		if err != nil {
			return nil, err
		}
		err = idea_dao.IdeaDao.UpdateAgreeValue(sessCtx, req.ProjectId, req.IdeaId, agreeCount, disagreeCount)
		if err != nil {
			return nil, err
		}
		return &project_idea_api.SetAppraiseResponse{
			Code: project_idea_api.SetAppraiseResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addSetAppraiseEvent(sessionItem, req, projectItem, ideaItem, nowTime)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateIdeaNotice{
		ProjectId: req.ProjectId,
		IdeaId:    req.IdeaId,
	})
	return ret.(*project_idea_api.SetAppraiseResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) CancelAppraise(ctx context.Context, req *project_idea_api.CancelAppraiseRequest) (*project_idea_api.CancelAppraiseResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.CancelAppraiseResponse{
			Code:   project_idea_api.CancelAppraiseResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.CancelAppraiseResponse{
			Code:   project_idea_api.CancelAppraiseResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.CancelAppraiseResponse{
			Code:   project_idea_api.CancelAppraiseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.CancelAppraiseResponse{
			Code:   project_idea_api.CancelAppraiseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	ideaItem, err := idea_dao.IdeaDao.Get(ctx, req.ProjectId, req.IdeaId)
	if err != nil {
		return &project_idea_api.CancelAppraiseResponse{
			Code:   project_idea_api.CancelAppraiseResponse_CODE_NO_IDEA,
			ErrMsg: "知识点不存在",
		}, nil
	}

	appraiseItem, err := idea_dao.AppraiseDao.Get(ctx, req.IdeaId, sessionItem.UserId)
	if err != nil { //投票不存在
		return &project_idea_api.CancelAppraiseResponse{
			Code: project_idea_api.CancelAppraiseResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.AppraiseDao.Remove(sessCtx, req.IdeaId, sessionItem.UserId)
		if err != nil {
			return nil, err
		}
		agreeCount, err := idea_dao.AppraiseDao.CountByIdea(sessCtx, req.IdeaId, uint32(project_idea_api.APPRAISE_TYPE_APPRAISE_AGREE))
		if err != nil {
			return nil, err
		}
		disagreeCount, err := idea_dao.AppraiseDao.CountByIdea(sessCtx, req.IdeaId, uint32(project_idea_api.APPRAISE_TYPE_APPRAISE_DIS_AGREE))
		if err != nil {
			return nil, err
		}
		err = idea_dao.IdeaDao.UpdateAgreeValue(sessCtx, req.ProjectId, req.IdeaId, agreeCount, disagreeCount)
		if err != nil {
			return nil, err
		}
		return &project_idea_api.CancelAppraiseResponse{
			Code: project_idea_api.CancelAppraiseResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addCancelAppraiseEvent(sessionItem, projectItem, ideaItem, appraiseItem, time.Now().UnixNano()/1e6)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateIdeaNotice{
		ProjectId: req.ProjectId,
		IdeaId:    req.IdeaId,
	})
	return ret.(*project_idea_api.CancelAppraiseResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) ListAppraise(ctx context.Context, req *project_idea_api.ListAppraiseRequest) (*project_idea_api.ListAppraiseResponse, error) {
	emptyList := []*project_idea_api.Appraise{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.ListAppraiseResponse{
			Code:         project_idea_api.ListAppraiseResponse_CODE_WRONG_SESSION,
			ErrMsg:       "会话不存在",
			AppraiseList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.ListAppraiseResponse{
			Code:         project_idea_api.ListAppraiseResponse_CODE_NO_PROJECT,
			ErrMsg:       "项目不存在",
			AppraiseList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.ListAppraiseResponse{
			Code:         project_idea_api.ListAppraiseResponse_CODE_NO_PERMISSION,
			ErrMsg:       "没有权限",
			AppraiseList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}
	exist, err := idea_dao.IdeaDao.Exist(ctx, req.ProjectId, req.IdeaId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_idea_api.ListAppraiseResponse{
			Code:         project_idea_api.ListAppraiseResponse_CODE_NO_IDEA,
			ErrMsg:       "知识点不存在",
			AppraiseList: emptyList,
		}, nil
	}
	appraiseItemList, err := idea_dao.AppraiseDao.List(ctx, req.IdeaId)
	if err != nil {
		return nil, err
	}
	//补充用户信息
	userIdList := []string{}
	for _, appraiseItem := range appraiseItemList {
		userIdList = append(userIdList, appraiseItem.MemberUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//生成结果
	infoList := []*project_idea_api.Appraise{}
	for _, appraiseItem := range appraiseItemList {
		info := appraiseItem.ToAppraise()
		userItem, ok := userItemMap[appraiseItem.MemberUserId]
		if ok {
			info.MemberDisplayName = userItem.BasicInfo.DisplayName
			info.MemberLogoUri = userItem.BasicInfo.LogoUri
		}
		infoList = append(infoList, info)
	}
	return &project_idea_api.ListAppraiseResponse{
		Code:         project_idea_api.ListAppraiseResponse_CODE_OK,
		AppraiseList: infoList,
	}, nil
}
